import { Callout, Card, Cards } from 'nextra/components';

# Fixture Modules

A fixture is a React Component or any React Node. A fixture module contains one or more fixtures.

<Cards>
  <Card title="Node Fixtures" href="#node-fixtures" />
  <Card title="Component Fixtures" href="#component-fixtures" />
  <Card title="Multi-Fixtures" href="#multi-fixtures" />
  <Card title="MDX Fixtures" href="#mdx-fixtures" />
</Cards>

## Node Fixtures

<Callout type="info">
  Think of Node fixtures as the return value of a function component, or the
  first argument to `React.render`.
</Callout>

```jsx filename="Button.fixture.jsx"
export default <Button disabled>Click me</Button>;
```

## Component Fixtures

Component fixtures are just React function components with no props. They enable using Hooks inside fixtures, which is powerful for simulating state with stateless components.

```jsx filename="CounterButton.fixture.jsx"
export default () => {
  const [count, setCount] = useState(0);

  return <CounterButton count={count} increment={() => setCount(count + 1)} />;
};
```

## Multi-Fixtures

A fixture module can also export multiple fixtures if the default export is an object. The object's property names will show up as fixture names in the Cosmos UI.

{/* prettier-ignore */}
```jsx filename="Button.fixture.jsx"
export default {
  'Primary': <PrimaryButton>Click me</PrimaryButton>,

  'Primary Disabled': <PrimaryButton disabled>Click me</PrimaryButton>,

  'Secondary': <SecondaryButton>Click me</SecondaryButton>,

  'Secondary Disabled': <SecondaryButton disabled>Click me</SecondaryButton>,
};
```

### Component Multi-Fixtures

Multi-Fixtures can also contain components.

```jsx filename="CounterButton.fixture.jsx"
export default {
  'Counter x1': () => {
    const [count, setCount] = useState(0);
    return (
      <CounterButton count={count} increment={() => setCount(count + 1)} />
    );
  },

  'Counter x2': () => {
    const [count, setCount] = useState(0);
    return (
      <CounterButton count={count} increment={() => setCount(count + 2)} />
    );
  },
};
```

Using arrow functions in Multi-Fixtures will cause [eslint-plugin-react-hooks](https://www.npmjs.com/package/eslint-plugin-react-hooks) to complain about using hooks inside unnamed components. To avoid having to suppress these warnings in every fixture you can do one of the following:

1. Use ESLint `overrides` to disable this rule inside Cosmos fixtures. [Here is an example.](https://github.com/react-cosmos/react-cosmos/blob/bcc09106ef7a010e1c305119385c739773571574/.eslintrc.cjs#L31-L36)
2. Name your component functions, like this: `'my fixture': function MyFixture() {`.
3. Create regular component functions and attach them to the default fixture export (see below).

```jsx filename="CounterButton.fixture.jsx"
function CounterX1() {
  const [count, setCount] = useState(0);
  return <CounterButton count={count} increment={() => setCount(count + 1)} />;
}

function CounterX2() {
  const [count, setCount] = useState(0);
  return <CounterButton count={count} increment={() => setCount(count + 2)} />;
}

export default { CounterX1, CounterX2 };
```

### Dynamic Multi-Fixtures

Multi-Fixtures can be created dynamically. This is useful for generating fixtures from data.

```jsx filename="Button.fixture.jsx"
const fixtures = {};

for (let color of ['red', 'green', 'blue']) {
  fixtures[color] = <Button color={color}>Click me</Button>;
}

export default fixtures;
```

## MDX Fixtures

Creating MDX fixtures is as easy as [configuring MDX for your bundler](https://mdxjs.com/docs/getting-started/#bundler) and using the `.mdx` (or `.md`) file extension for your fixture files.

<Callout type="info">
  Both Vite and Webpack
  [examples](https://github.com/react-cosmos/react-cosmos/tree/main/examples)
  feature MDX fixtures configured with `@mdx-js/rollup` and `@mdx-js/loader`
  respectively.
</Callout>
